package com.ziiwee.reduce.rest.jpa;

import com.ziiwee.reduce.commons.utils.ExportUtil;
import com.ziiwee.reduce.commons.utils.StringUtil;
import com.ziiwee.reduce.rest.Resource;
import com.ziiwee.reduce.rest.ResourceController;
import com.ziiwee.reduce.rest.ResourceService;
import com.ziiwee.reduce.rest.auto.DefaultResourceMapping;
import com.ziiwee.reduce.rest.auto.ResourceInfo;
import com.ziiwee.reduce.rest.auto.ResourceInfoModel;
import com.ziiwee.reduce.rest.auto.ResourceMapping;
import com.ziiwee.reduce.rest.utils.RestUtil;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Import;
import org.springframework.core.ResolvableType;
import org.springframework.util.Assert;

import javax.persistence.EntityManager;
import javax.persistence.metamodel.EntityType;
import javax.persistence.metamodel.Metamodel;
import java.util.List;

@Configuration
@Import(JpaDataAccessor.class)
public class RestJpaConfiguration {

    @Bean
    @ConditionalOnMissingBean(ResourceMapping.class)
    @Autowired(required = false)
    public ResourceMapping resourceMapping(EntityManager entityManager, JpaDataAccessor jpaDataAccessor, List<ResourceService<?, ?>> services) {
        DefaultResourceMapping mapping = new DefaultResourceMapping();
        for (EntityType<?> entity : entityManager.getMetamodel().getEntities()) {
            Class<?> javaType = entity.getJavaType();
            ResourceInfo resourceInfo = createResourceInfo(javaType, jpaDataAccessor);
            if (resourceInfo != null) {
                mapping.register(resourceInfo);
            }
        }
        for (ResourceService<?, ?> service : services) {
            if(! (service instanceof ResourceController)){
                mapping.register(service);
            }
        }
        return mapping;
    }

    private ResourceInfo createResourceInfo(Class<?> type, JpaDataAccessor jpaDataAccessor) {
        if (!ExportUtil.isExport(type)) {
            return null;
        }
        List<ResolvableType> args = RestUtil.getTypeArgsByClass(type, Resource.class);
        Class<?> idType = args.get(0).resolve();
        Assert.notNull(idType, "无法获取 Resource 的 Id 类型");
        ResourceInfoModel info = new ResourceInfoModel();
        info.setName(StringUtil.firstToLowerCase(type.getSimpleName()));
        info.setType(type);
        info.setIdType(idType);
        info.setService(new JpaResourceService<>(RestUtil.asPersistentResourceType(type), jpaDataAccessor));
        info.setCommonService(true);
        return info;
    }

}
